#ifndef AVALON_ENUMERATOR_HPP
#define AVALON_ENUMERATOR_HPP
#include "Avalon/Base/Base.hpp"

namespace Avalon {

  /*! \struct Enumerator
   *  \brief Encapsulates an enum in a type safe manner.
   */
  template<typename T, typename E = typename T::Type>
  class Enumerator : public T {
    public:

      //! The underlying enum being encapsulated.
      typedef typename T::Type Type;

      //! Used to represent no enumeration.
      static const Enumerator NONE;

      //! Returns the Enumerator for a given value.
      /*!
        \param value The raw value to get the Enumerator for.
        \return The Enumerator corresponding to the specified <i>value</i>.
      */
      template<typename R>
      static Enumerator FromValue(R value) {
        return Enumerator(static_cast<Type>(value));
      }

      //! Constructs an uninitialized Enumerator.
      Enumerator()
          : m_value(static_cast<E>(-1)) {}

      Enumerator(Type value)
          : m_value(value) {}

      //! Returns the encapsulated value.
      /*!
        \return The encapsulated value.
      */
      E GetValue() const {
        return m_value;
      }

      //! Compares two Enumerators for equality.
      /*!
        \param rhs The right hand side of the equality.
        \return <code>true</code> iff the two types are equal.
      */
      bool operator ==(Enumerator rhs) const {
        return m_value == rhs.m_value;
      }

      //! Compares two Enumerators for inequality.
      /*!
        \param rhs The right hand side of the inequality.
        \return <code>true</code> iff the two types are unequal.
      */
      bool operator !=(Enumerator rhs) const {
        return m_value != rhs.m_value;
      }

      //! Less than operator.
      /*!
        \param rhs The right hand side of the operation.
        \return <code>true</code> iff this is less than <i>rhs</i>.
      */
      bool operator <(Enumerator rhs) const {
        return m_value < rhs.m_value;
      }

      //! Less than or equal to operator.
      /*!
        \param rhs The right hand side of the operation.
        \return <code>true</code> iff this is less than or equal to <i>rhs</i>.
      */
      bool operator <=(Enumerator rhs) const {
        return m_value <= rhs.m_value;
      }

      //! Greater than operator.
      /*!
        \param rhs The right hand side of the operation.
        \return <code>true</code> iff this is greater than <i>rhs</i>.
      */
      bool operator >(Enumerator rhs) const {
        return m_value > rhs.m_value;
      }

      //! Greater than or equal to operator.
      /*!
        \param rhs The right hand side of the operation.
        \return <code>true</code> iff this is greater than or equal to
                <i>rhs</i>.
      */
      bool operator >=(Enumerator rhs) const {
        return m_value >= rhs.m_value;
      }

    private:
      E m_value;
  };

  //! Defines the NONE Enumerator.
  template<typename T, typename E>
  const Enumerator<T, E> Enumerator<T, E>::NONE(static_cast<E>(-1));
}

#endif // AVALON_ENUMERATOR_HPP
